package com.cm.etax.tianjin;

import com.cm.etax.BaseEtax;
import com.cm.etax.BaseFunction;
import com.cm.etax.FunctionResult;
import com.cm.etax.exceptions.EtaxException;
import com.cm.kits.DateTimeKits;
import com.cm.kits.HttpTool;
import com.cm.kits.JacksonKits;
import com.cm.kits.oss.OssKits;
import com.fasterxml.jackson.databind.node.ArrayNode;
import lombok.Data;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * 查询完税证明方法
 *
 * @author LWang 2023.02.02
 * @since 1.0.0
 */
public class QueryDutyPaidProofFunction extends BaseFunction {
    public QueryDutyPaidProofFunction(BaseEtax etax) {
        super(etax);
    }

    /**
     * 查询完税凭证
     *
     * @param taxpayerId 纳税人登记序号
     * @param startDate  开始时间
     * @param endDate    结束时间
     * @return 保存到 OSS 中的文件 ID
     */
    public FunctionResult<String> queryDutyPaidProof(String taxpayerId, String startDate, String endDate) {
        // 进入功能处理流程
        try {
            var menuFunction = etax().function(MenuFunction.class);
            // 切换主菜单
            var choiceMainMenuResult = menuFunction.choiceMainMenu("我要办税", "证明开具");
            if (!choiceMainMenuResult.success()) {
                return new FunctionResult<>(false, choiceMainMenuResult.message(), null);
            }
            // 切换功能菜单
            var choiceFunctionMenuResult = menuFunction.choiceFunctionMenu("开具税收完税（费）证明（文书式）");
            if (!choiceFunctionMenuResult.success()) {
                return new FunctionResult<>(false, choiceFunctionMenuResult.message(), null);
            }
            // 切换进入实际工作 iFrame
            rpa().switchToFrame(By.id("iframeContainerPaneId"), WAIT_TIME);
            // 选择企业，并下一步进行查询
            rpa().click(By.cssSelector("input[type=\"radio\"][value=\"%s\"]".formatted(taxpayerId)), WAIT_TIME);
            rpa().click(By.cssSelector("input.next[type=\"button\"][value=\"下一步\"]"), WAIT_TIME);
            // 设置查询条件
            rpa().click(By.cssSelector("input#dygs[value=\"1\"]"), WAIT_TIME);
            rpa().click(By.id("nspzhkzl"), WAIT_TIME);
            rpa().findElementWithInnerText("税收完税证明（文书式）", By.cssSelector("select#nspzhkzl option"), WAIT_TIME).click();
            rpa().executeJavaScript("document.querySelector('#skssqq').value=arguments[0]", Object.class, startDate);
            rpa().executeJavaScript("document.querySelector('#skssqz').value=arguments[0]", Object.class, endDate);
            rpa().executeJavaScript("""
                    (function() {
                        try {
                            window.alert = function() {}
                            window.confirm = function() {return true;}
                        } catch (e) {
                        }
                    })();
                    """, Object.class);
            rpa().newHar();
            rpa().click(By.cssSelector("input.last[value=\"查询\"]"), WAIT_TIME);
            var response = rpa().jsonListen("WsbsWebBn/wsbsWszmAction_queryJks.do");
            var code = response.get("returnCode").asText(CODE_ERROR);
            var rows = response.get("rows");
            if (!Objects.equals(code, CODE_SUCCESS)) {
                throw new EtaxException("未查询到符合要求的数据，请检查对应的税款是否入库");
            }
            if (rows instanceof ArrayNode arrayNode && arrayNode.size() <= 0) {
                throw new EtaxException("未查询到符合要求的数据，请检查对应的税款是否入库");
            }
            // 替换页面中的 savDataCallback 方法，不执行页面跳转操作
            rpa().executeJavaScript("window.savDataCallback = function(applicationId){}", Object.class);
            var sn = StringUtils.EMPTY;
            var submit = rpa().findElement(By.cssSelector("input.next[value=\"下一步\"]"));
            while (StringUtils.isBlank(sn)) {
                rpa().newHar();
                submit.click();
                response = rpa().jsonListen("WsbsWebBn/wsbsWszmAction_saveWszmxx.do");
                if (Objects.isNull(response)) {
                    throw new EtaxException("开具完税证明过程出现异常，请重新登录！");
                }
                var result = response.get("result");
                if (Objects.isNull(result)) {
                    throw new EtaxException("开具完税证明过程出现异常，请重新登录！");
                }
                var saveResult = JacksonKits.toBean(result.asText("{}"), SaveResult.class);
                assert saveResult != null;
                if (Objects.equals("modify", saveResult.flag)) {
                    throw new EtaxException("请勿篡改完税信息！");
                }
                if (Objects.equals("session", saveResult.flag)) {
                    throw new EtaxException("当前登录用户异常，请重新登录！");
                }
                if (Objects.equals("N", saveResult.flag)) {
                    sn = saveResult.lsh;
                    break;
                }
                rpa().sleep(SLEEP_TIME);
            }
            // 使用流水号查询完税证明
            return downloadDutyPaidProof(sn);
        } catch (Exception e) {
            return handleException(e, "查询完税证明失败，");
        } finally {
            rpa().switchToParent();
        }
    }

    /**
     * 下载完税凭证
     *
     * @param sn 流水号
     * @return 保存在 SSO 中的文件编号
     */
    private FunctionResult<String> downloadDutyPaidProof(String sn) throws NoSuchAlgorithmException, IOException, InterruptedException, KeyManagementException, URISyntaxException {
        rpa().switchToParent();
        var menuFunction = etax().function(MenuFunction.class);
        // 切换主菜单
        var choiceMainMenuResult = menuFunction.choiceMainMenu("我要办税", "证明开具");
        if (!choiceMainMenuResult.success()) {
            return new FunctionResult<>(false, choiceMainMenuResult.message(), null);
        }
        // 切换功能菜单
        var choiceFunctionMenuResult = menuFunction.choiceFunctionMenu("查询已开具税收完税（费）证明（文书式）");
        if (!choiceFunctionMenuResult.success()) {
            return new FunctionResult<>(false, choiceFunctionMenuResult.message(), null);
        }
        rpa().switchToFrame(By.id("iframeContainerPaneId"), WAIT_TIME);
        // 设置查询参数
        rpa().sendKey(By.id("sqsjq"), "1970-01-01", true, WAIT_TIME);
        rpa().sendKey(By.id("sqsjz"), DateTimeKits.currentDay(), true, WAIT_TIME);
        rpa().sendKey(By.id("lsh"), sn, true, WAIT_TIME);
        rpa().newHar();
        rpa().findElement(By.cssSelector("input[type=\"button\"][value=\"查询\"]"), WAIT_TIME).click();
        rpa().listen("wsbsWszmAction_queryYkjWszmxx.do");
        // 查询表格
        var rows = rpa().findElements(By.cssSelector("div.base table.table tbody tr"), WAIT_TIME);
        for (var row : rows) {
            WebElement downloadButton;
            try {
                downloadButton = row.findElement(By.cssSelector("input.applybtn[value=\"下载证明\"]"));
            } catch (NoSuchElementException e) {
                continue;
            }
            if (rpa().inElementText(row, sn)) {
                var downloadInfo = downloadButton.getAttribute("onclick");
                var matcher = Pattern.compile("download\\('(.+?)','(.+?)'\\)").matcher(downloadInfo);
                if (matcher.find()) {
                    return new FunctionResult<>(true, "下载完成完税证明成功。", downloadPdf(matcher.group(1), matcher.group(2)));
                } else {
                    throw new EtaxException("根据流水号下载晚熟凭证失败，流水号 " + sn + "对应的完税证明不存在！");
                }
            }
        }
        return null;
    }

    /**
     * 下载完税凭证
     *
     * @param applicationId 应用 ID
     * @param typeId        种类 ID
     * @return OSS 资源 ID
     */
    private String downloadPdf(String applicationId, String typeId) throws NoSuchAlgorithmException, KeyManagementException, IOException, InterruptedException {
        var url = "%sWsbsWebBn/wsbsWszmAction_showPdf.do?applicationId=%s&zlId=%s".formatted(config().getDomain(), applicationId, typeId);
        var httpClient = HttpTool.build();
        var downloadInfo = httpClient.download(url, "pdf");
        if (!downloadInfo.getKey().equals(HttpStatus.SC_OK)) {
            throw new EtaxException("无法下载完税证明，对应的文件不存在！");
        }
        try {
            return OssKits.upload(downloadInfo.getValue().toFile());
        } finally {
            FileUtils.delete(downloadInfo.getValue().toFile());
        }
    }

    private final static String CODE_ERROR = "99";
    private final static String CODE_SUCCESS = "00";

    @Data
    public static class SaveResult {
        private String flag;
        private String lsh;
    }
}
